package com.yifeng.servlet;


import com.google.gson.*;
import com.yifeng.common.Result;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.time.LocalDateTime;

public abstract class BaseServlet extends HttpServlet {

    /*
    负责人：

    功能：Gson 实例，用于在整个应用中统一进行 JSON 与 Java 对象之间的序列化和反序列化

    参数：无

    返回值:无
    */
// 在 BaseServlet 类中添加静态 Gson 实例
    private static final Gson GSON = new GsonBuilder()
            .registerTypeAdapter(LocalDateTime.class, (JsonDeserializer<LocalDateTime>) (json, type, jsonDeserializationContext) ->
                    LocalDateTime.parse(json.getAsString()))
            .registerTypeAdapter(LocalDateTime.class, (JsonSerializer<LocalDateTime>) (localDateTime, type, jsonSerializationContext) ->
                    new JsonPrimitive(localDateTime.toString()))
            .create();

    /*
    负责人：

    功能：重写 HttpServlet 的 service 方法，统一设置请求/响应编码、CORS 跨域头，并调用子类业务逻辑，同时捕获全局异常

    参数：req - HTTP 请求对象；resp - HTTP 响应对象

    返回值:无（通过 resp 直接输出 JSON 响应）
    */
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        // 统一设置请求编码（对表单有效）和响应类型
        req.setCharacterEncoding("UTF-8");
        resp.setCharacterEncoding("UTF-8");
        resp.setContentType("application/json;charset=UTF-8");
        resp.setHeader("Access-Control-Allow-Origin", "*"); // 允许跨域（开发阶段）


        // CORS 配置
        resp.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
//        resp.setHeader("Access-Control-Max-Age", "3600");
        resp.setHeader("Access-Control-Allow-Headers", "Authorization, Content-Type, X-Requested-With, Accept");
//        resp.setHeader("Access-Control-Allow-Credentials", "true"); // 如果需要携带 cookie

        // 如果是预检请求（OPTIONS），直接返回 200，不继续执行业务逻辑
        if ("OPTIONS".equalsIgnoreCase(req.getMethod())) {
            resp.setStatus(HttpServletResponse.SC_OK);
            return;
        }

        try {
            // 调用子类实现的具体业务逻辑
            doHandle(req, resp);
        } catch (Exception e) {
            // 统一捕获异常并返回错误响应
            handleError(resp, e);
        }
    }

    /*
    负责人：

    功能：抽象方法，由子类实现具体业务逻辑，是所有 API 接口的统一处理入口

    参数：req - HTTP 请求对象；resp - HTTP 响应对象

    返回值:无（子类通过 resp 输出响应）
    */
    protected abstract void doHandle(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException;

    /*
    负责人：

    功能：从 HTTP 请求体中读取 JSON 字符串，并使用 Gson 反序列化为指定类型的 Java 对象

    参数：req - HTTP 请求对象；clazz - 目标 Java 类的 Class 对象（如 User.class）

    返回值:反序列化后的 Java 对象；若请求体为空则返回 null；若 JSON 格式错误则抛出 IOException
    */
    protected <T> T readJsonBody(HttpServletRequest req, Class<T> clazz) throws IOException {
        // 获取请求体的字符输入流
        BufferedReader reader = req.getReader();
        StringBuilder jsonBuffer = new StringBuilder();
        String line;
        while ((line = reader.readLine()) != null) {
            jsonBuffer.append(line);
        }
        String json = jsonBuffer.toString().trim();

        // 如果请求体为空，返回 null（可根据业务决定是否抛异常）
        if (json.isEmpty()) {
            return null;
        }

        // 使用 Gson 将 JSON 字符串转换为指定类型的对象
        try {
            return GSON.fromJson(json, clazz);
        } catch (Exception e) {
            // JSON 格式错误或字段不匹配
            throw new IOException("无效的 JSON 格式: " + e.getMessage(), e);
        }
    }

    /*
    负责人：

    功能：将任意 Java 对象序列化为 JSON 字符串，并写入 HTTP 响应体

    参数：resp - HTTP 响应对象；obj - 要序列化的 Java 对象（通常为 Result 封装对象）

    返回值:无（直接通过 PrintWriter 输出到客户端）
    */
    protected void writeJson(HttpServletResponse resp, Object obj) throws IOException {
        PrintWriter out = resp.getWriter();
        resp.setContentType("application/json;charset=UTF-8");
        // 使用 Gson 将对象转换为 JSON，会忽略所有null值字段
        out.println(GSON.toJson(obj));
        out.flush();
    }

    /*
    负责人：

    功能：快速构造并返回一个成功的 JSON 响应（code=200），封装业务数据

    参数：resp - HTTP 响应对象；data - 要返回的成功数据（如用户列表、详情等）

    返回值:无（通过 writeJson 输出 Result.success(data) 的 JSON）
    */
    protected void success(HttpServletResponse resp, Object data) throws IOException {
        writeJson(resp, Result.success(data));
    }

    /*
    负责人：

    功能：快速构造并返回一个失败的 JSON 响应（code=400），携带错误提示信息

    参数：resp - HTTP 响应对象；message - 错误提示字符串（如“参数缺失”）

    返回值:无（通过 writeJson 输出 Result.fail(message) 的 JSON）
    */
    protected void fail(HttpServletResponse resp, String message) throws IOException {
        writeJson(resp, Result.fail(message));
    }

    /*
    负责人：

    功能：统一处理未捕获的异常，打印堆栈跟踪（开发阶段），并向客户端返回通用错误响应

    参数：resp - HTTP 响应对象；e - 捕获的异常对象

    返回值:无（输出固定错误信息的 JSON 响应）
    */
    private void handleError(HttpServletResponse resp, Exception e) throws IOException {
        e.printStackTrace(); // 实际项目应使用日志框架（如 SLF4J）
        writeJson(resp, Result.fail("服务器内部错误，请稍后再试"));
    }
}